package com.CMUBiS.PageControllers;

import java.util.ArrayList;

import javax.servlet.http.HttpServletRequest;

import com.CMUBiS.Data.Error;
import com.CMUBiS.Data.GlobalErrors;
import com.CMUBiS.Data.GlobalVars;
import com.CMUBiS.util.Address;
import com.CMUBiS.util.CheckInputs;
import com.CMUBiS.util.StopWatch;
import com.CMUBiS.util.User;
/**
 * This class processes the data for the update user details page
 * 
 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
 * @version 0.1
 * @since 0.1
 * @date 04/05/2011
 */
public class UpdateUserDetailsController extends PageController{
	// Variables passed in the request
	private String email1 = null;
	private String email2 = null;
	private String password1 = null;
	private String password2 = null;
	private String firstname = null;
	private String lastname = null;
	private String street = null;
	private String town = null;
	private String zip = null;
	private String state = null;
	private int userID = -1;
	private String authToken = null;
	private int addressID = -1;
	private Boolean addressIsDefault = null;
	
	// Structures to hold the DB data
	private ArrayList<String[]> states = null;
	private Boolean hasAddress = Boolean.FALSE;
	
	// Structures to hold the parsed page data
	private String[] stateSelections = null;
	private String redirectURL = null;
	
	/**
	 * This method checks the page for any input errors that may have come from Client generator error
	 * These would need to be check in real life to stop users attempting to hack and mess with things
	 * This page has lots of variables to check
	 * 
	 * @param request
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void checkInputs(HttpServletRequest request){
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		if(request != null){
			super.checkInputs(request);
			
			// Get the userID (if exists), we will pass it along to the next pages
			try{
				this.userID = CheckInputs.checkUserID(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
			}
			
			// Get the authToken (if exists), we will pass it along to the next pages
			try{
				this.authToken = CheckInputs.checkAuthToken(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
			}
			
			// Check the e-mail addresses
			try{
				this.email1 = CheckInputs.checkEmailsVaild(request);
				this.email2 = email1;
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
				
				// As the emails were not correct we'll fill the box with the user's old, bad data
				this.email1 = CheckInputs.getParameter(request, "email1");
				this.email2 = CheckInputs.getParameter(request, "email2");
			}
			
			// Check the passwords
			this.password1 = CheckInputs.getParameter(request, "password1");
			this.password2 = CheckInputs.getParameter(request, "password2");
			
			if(this.password1.equals(EMPTY) || this.password2.equals(EMPTY)){
				if(!errors.contains(GlobalErrors.passwordEmpty))
					errors.add(GlobalErrors.passwordEmpty);
				
			}
			else if(!this.password1.equals(password2)){
				if(!errors.contains(GlobalErrors.passwordDifferent))
					errors.add(GlobalErrors.passwordDifferent);
			}
			
			// Get the firstname
			this.firstname = CheckInputs.getParameter(request, "firstname");
			
			if(firstname.equals(EMPTY)){
				if(!errors.contains(GlobalErrors.firstnameEmpty))
					errors.add(GlobalErrors.firstnameEmpty);
			}
			
			// Get the lastname
			this.lastname = CheckInputs.getParameter(request, "lastname");
			
			if(lastname.equals(EMPTY)){
				if(!errors.contains(GlobalErrors.lastnameEmpty))
					errors.add(GlobalErrors.lastnameEmpty);
			}
			
			// Get the street
			this.street = CheckInputs.getParameter(request, "street");
			
			if(street.equals(EMPTY)){
				if(!errors.contains(GlobalErrors.streetEmpty))
					errors.add(GlobalErrors.streetEmpty);
			}
			
			// Get the town
			this.town = CheckInputs.getParameter(request, "town");
			
			if(town.equals(EMPTY)){
				if(!errors.contains(GlobalErrors.townEmpty))
					errors.add(GlobalErrors.townEmpty);
			}
			
			// Get the zip
			try{
				this.zip = CheckInputs.checkZip(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
				
				// As the zip was not correct we'll fill the box with the user's old, bad data
				this.zip = CheckInputs.getParameter(request, "zip");
			}
			
			// Check the state
			try{
				this.state = CheckInputs.checkState(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
				
				// As the state was not correct set a default
				this.state = "0";
			}

			// Check the addressID
			try{
				this.addressID = CheckInputs.checkAddressID(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);

				this.addressID = -1;
			}
			
			// Get whether the address is the default (looking for 'true' or 'false')
			this.addressIsDefault = Boolean.parseBoolean(CheckInputs.getParameter(request, "addressIsDefault"));
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalGetParamTime += timer.getTimeTaken();
		}
	}

	/**
	 * This method get the data needed for the HTML4 page from the database
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void getHTML4Data() {	
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Get the list of states from the data base
		try{
			this.states = GlobalVars.db.getStates();
		}
		catch(Exception e){
			errors.add(new Error("RegisterUserControl: getHTML4data: could not read the states from the database", e));
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalDBtime += timer.getTimeTaken();
		}
	}

	/**
	 * This method processes all of the data that was read from the database such that it is ready to be printed
	 * on to the page. We try to do as much of the page logic here as possible
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void processHTML4() {
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		/*
		 * Make the state selections
		 */
		int stateNo;
		// If the state is a number and there are states read from the database we can make the list
		try{
			stateNo = Integer.parseInt(this.state);
			
			if(this.states != null){
				this.stateSelections = new String[this.states.size()+1];
				
				// Add the 'please select'
				this.stateSelections[0] = "<option value=\"0\""+ (stateNo==0?" SELECTED":"") + ">Please Select...</option>";
				
				// Add the other states
				int length = this.states.size();
				
				for(int i=0; i<length; i++){
					String[] state = this.states.get(i);
					this.stateSelections[i+1] = "<option value=\"" + state[0] + "\"" + (this.state.equals(state[0])?" SELECTED":"") + ">" + state[1] + " - " + state[2] + "</option>";
				}
			}
			else{
				this.stateSelections = new String[1];
				this.stateSelections[0] = "<option value=\"0\""+ (stateNo==0?" SELECTED":"") + ">Please Select...</option>";
			}
		}
		catch(Exception e){
			if(!errors.contains(GlobalErrors.stateNotAnInteger))
				errors.add(GlobalErrors.stateNotAnInteger);
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalProcessingTime += timer.getTimeTaken();
		}
	}
	
	/**
	 * Gets the HTML5 data from the database
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void getHTML5Data(){
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalDBtime += timer.getTimeTaken();
		}
	}
	
	/**
	 * Processes the HTML5 data that is needed to create the page
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void processHTML5(){
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalProcessingTime += timer.getTimeTaken();
		}
	}
	
	/**
	 * This method updates the user's information in the database
	 * 
	 * @return boolean true if the user was successfully updated
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public boolean updateUser(){
		// If there are no errors on the page and the userID and password are correct we can update the database
		if(this.errors.size()==0)
			if(GlobalVars.db.checkAuthToken(this.userID, this.authToken)){
				//The state must be correct since there weren't any errors
				int stateNo = -1;
				
				try{
					stateNo = Integer.valueOf(this.state);
				}
				catch(NumberFormatException e){
					if(!errors.contains(e))
						errors.add(GlobalErrors.stateNotAnInteger);
				}
				
				// Update the user and create the redirect URL
				if(stateNo >=0 ){     
					boolean retVal = GlobalVars.db.updateUser(Integer.toString(this.userID), "",this.password1, this.email1,
										this.firstname, this.lastname);
					
					boolean retVal2 = GlobalVars.db.updateAddress(this.addressID, userID, street, town, zip, stateNo, addressIsDefault);
					
					if(retVal && retVal2) this.createRedirectURL();
					
					return retVal && retVal2;
				}
			}
			else if(!errors.contains(GlobalErrors.incorrectAuthToken))
					errors.add(GlobalErrors.incorrectAuthToken);
		
		return false;
	}
	
	//TODO: we shouldn't really EVER read the password. It should be encrypted and we should compare the hash
	public void getUserInfo(){
		// If the username and authToken are correct we can read the user's data
		if(GlobalVars.db.checkAuthToken(this.userID, this.authToken)){
			// Get the data from the database
			User user = GlobalVars.db.getUser(this.userID);
			
			// Read out the user's details
			this.email1 = user.getEmail();
			this.email2 = this.email1;
			this.password1 = user.getPassword();
			this.password2 = this.password1;
			this.firstname = user.getFirstName();
			this.lastname = user.getLastName();
			
			// Read out their default address
			Address address = GlobalVars.db.getDefaultAddress(this.userID);
			if(address != null){
				this.hasAddress = Boolean.TRUE;
				this.addressID = address.getId();
				this.street = address.getStreet();
				this.town = address.getTown();
				this.zip = address.getZip();
				this.state = String.valueOf(address.getState());
			}
		}
		else if(!errors.contains(GlobalErrors.cannotAuthenticate))
			errors.add(GlobalErrors.cannotAuthenticate);
	}
	
	/**
	 * If we successfully insert the user then we'll need to forward them on to the next page.
	 * We'll create the URL here
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	private void createRedirectURL(){
		this.redirectURL = "./myaccount?userID=" + this.userID + "&authToken=" + this.authToken;
	}
	
	/**
	 * Returns the password1 sent to the page
	 * 
	 * @return String the password1 sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getPassword1(){
		return this.password1;
	}
	
	/**
	 * Returns the password2 sent to the page
	 * 
	 * @return String the password2 sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getPassword2(){
		return this.password2;
	}
	
	/**
	 * Returns the email1 sent to the page
	 * 
	 * @return String the email1 sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getEmail1(){
		return this.email1;
	}
	
	/**
	 * Returns the email2 sent to the page
	 * 
	 * @return String email2 sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getEmail2(){
		return this.email2;
	}
	
	/**
	 * Returns the firstname sent to the page
	 * 
	 * @return String the firstname sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getFirstname(){
		return this.firstname;
	}
	
	/**
	 * Returns the lastname sent to the page
	 * 
	 * @return String the lastname sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getLastname(){
		return this.lastname;
	}
	
	/**
	 * Returns the street sent to the page
	 * 
	 * @return String the street sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getStreet(){
		return this.street;
	}
	
	/**
	 * Returns the town sent to the page
	 * 
	 * @return String the town sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getTown(){
		return this.town;
	}
	
	/**
	 * Returns the zip sent to the page
	 * 
	 * @return String the zip sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getZip(){
		return this.zip;
	}
	
	/**
	 * Returns the zip code sent to the page
	 * 
	 * @return String the zip code sent to the page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getState(){
		return this.state;
	}
	
	/**
	 * Returns the states that can be selected by the user
	 * 
	 * @return Sting[] a list of states (in option list format) that the user can choose from
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String[] getStateSelections(){
		return this.stateSelections;
	}
	
	/**
	 * Returns the URL to be redirected to if the user successfully registers
	 * 
	 * @return String the next URL to redirect to
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getRedirectURL(){
		return this.redirectURL;
	}
	
	/**
	 * Returns the current userID as a String
	 * 
	 * @return String the userID
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getUserIDString(){
		return Integer.toString(this.userID);
	}
	
	/**
	 * Returns the authToken sent to the page
	 * 
	 * @return string the authToken
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getAuthTokenString(){
		return this.authToken;
	}
	
	public Boolean getHasAddress(){
		return this.hasAddress;
	}
	
	public int getAddressID(){
		return this.addressID;
	}
}
